package org.jeecg.modules.cosmetic.handler;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.cosmetic.constant.enums.IecicLinkedTypeEnum;
import org.jeecg.modules.cosmetic.entity.*;
import org.jeecg.modules.cosmetic.model.dto.*;
import org.jeecg.modules.cosmetic.model.vo.FormulaRiskUpdateVO;
import org.jeecg.modules.cosmetic.model.vo.IngredientUpdateVO;
import org.jeecg.modules.cosmetic.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author scx
 * @date 2022/7/15 3:30 下午
 */
@Service
@Slf4j
public class IngredientHandler {

    @Resource
    private ITSecurityEvaluationService securityEvaluationService;
    @Resource
    private ITRawmaterialService rawmaterialService;
    @Resource
    private ITProductMaterialService productMaterialService;
    @Resource
    private ITFormulaRiskService formulaRiskService;
    @Resource
    private ITFormulaService formulaService;
    @Resource
    private ITMaterialLinkedService materialLinkedService;

    /**
     * 产品实际成分含量列表
     *
     * @param productId
     * @return
     */
    public Result<List<IngredientContentDTO>> getActualPurityList(Long productId) {
        List<TSecurityEvaluation> tSecurityEvaluations = securityEvaluationService.list(new LambdaQueryWrapper<TSecurityEvaluation>()
                .eq(TSecurityEvaluation::getProductId, productId));
        if (CollectionUtils.isEmpty(tSecurityEvaluations)) {
            log.info("未查询到成分含量数据");
            return Result.OK(Lists.newArrayList());
        }
        return Result.ok(tSecurityEvaluations.stream().map(m -> {
            TRawmaterial tRawmaterial = rawmaterialService.getOne(new LambdaQueryWrapper<TRawmaterial>()
                    .eq(TRawmaterial::getIecicNum, m.getIecicNum()));
            return IngredientContentDTO.builder()
                    .cName(m.getCnName())
                    .eName(tRawmaterial.getIncicName())
                    .content(m.getContent())
                    .build();
        }).sorted(new Comparator<IngredientContentDTO>() {
            @Override
            public int compare(IngredientContentDTO o1, IngredientContentDTO o2) {
                return new BigDecimal(o2.getContent()).compareTo(new BigDecimal(o1.getContent()));
            }
        }).collect(Collectors.toList()));
    }

    /**
     * 各成分安全评估列表
     *
     * @param productId
     * @return
     */
    public Result<List<IngredientEvaluateDTO>> queryIngredientEvaluateList(Long productId) {
        List<TSecurityEvaluation> tSecurityEvaluations = securityEvaluationService.list(new LambdaQueryWrapper<TSecurityEvaluation>()
                .eq(TSecurityEvaluation::getProductId, productId));
        if (CollectionUtils.isEmpty(tSecurityEvaluations)) {
            log.info("未查询到成分含量数据");
            return Result.OK(Lists.newArrayList());
        }
        return Result.ok(tSecurityEvaluations.stream().map(m -> {
            IngredientEvaluateDTO ingredientEvaluateDTO = new IngredientEvaluateDTO();
            ingredientEvaluateDTO.setId(m.getId());
            ingredientEvaluateDTO.setProductId(m.getProductId());
            ingredientEvaluateDTO.setCName(m.getCnName());
            ingredientEvaluateDTO.setContent(m.getContent());
            ingredientEvaluateDTO.setTechnicalDesc(m.getTechnicalSpecification());
            ingredientEvaluateDTO.setAuthorityConclusion(m.getAuthorityConclusion());
            ingredientEvaluateDTO.setHighestUsage(m.getHighestHistoryUsage());
            ingredientEvaluateDTO.setEvaluatedConclusion(m.getEvaluatedConclusion());

            //查询成分关联的资料
            List<TMaterialLinked> materialLinked = materialLinkedService.list(new LambdaQueryWrapper<TMaterialLinked>()
                    .eq(TMaterialLinked::getLinkedId, m.getId())
                    .eq(TMaterialLinked::getLinkedType, IecicLinkedTypeEnum.CIR.getType()));
            if (CollectionUtils.isEmpty(materialLinked)) {
                return ingredientEvaluateDTO;
            }

            List<MaterialDTO> materialDTOS = materialLinked.stream().map(materialId -> {
                MaterialDTO materialDTO = new MaterialDTO();
                TProductMaterial productMaterial = productMaterialService.getById(materialId.getMaterialId());
                if (ObjectUtil.isEmpty(productMaterial)) {
                    return materialDTO;
                }
                BeanUtils.copyProperties(productMaterial, materialDTO);
                if (productMaterial.getProductId() == null) {
                    TProductMaterial material = productMaterialService.getOne(new LambdaQueryWrapper<TProductMaterial>()
                            .eq(TProductMaterial::getProductId, productId)
                            .orderByDesc(TProductMaterial::getIdxNum)
                            .last("limit 1"));
                    materialDTO.setIdxNum(material.getIdxNum() + 1);
                }
                return materialDTO;
            }).collect(Collectors.toList());
            ingredientEvaluateDTO.setMaterialList(materialDTOS);
            return ingredientEvaluateDTO;
        }).sorted(new Comparator<IngredientEvaluateDTO>() {
            @Override
            public int compare(IngredientEvaluateDTO o1, IngredientEvaluateDTO o2) {
                return new BigDecimal(o2.getContent()).compareTo(new BigDecimal(o1.getContent()));
            }
        }).collect(Collectors.toList()));
    }

    /**
     * 查询成分信息详情
     *
     * @param id
     * @return
     */
    public Result<IngredientEvaluateDTO> queryIngredientEvaluateDetail(Long id) {
        TSecurityEvaluation securityEvaluation = securityEvaluationService.getById(id);
        Optional.ofNullable(securityEvaluation).orElseThrow(() -> new JeecgBootException("该成分信息不存在"));

        IngredientEvaluateDTO ingredientEvaluateDTO = new IngredientEvaluateDTO();
        ingredientEvaluateDTO.setId(securityEvaluation.getId());
        ingredientEvaluateDTO.setProductId(securityEvaluation.getProductId());
        ingredientEvaluateDTO.setCName(securityEvaluation.getCnName());
        ingredientEvaluateDTO.setContent(securityEvaluation.getContent());
        ingredientEvaluateDTO.setTechnicalDesc(securityEvaluation.getTechnicalSpecification());
        ingredientEvaluateDTO.setAuthorityConclusion(securityEvaluation.getAuthorityConclusion());
        ingredientEvaluateDTO.setHighestUsage(securityEvaluation.getHighestHistoryUsage());
        ingredientEvaluateDTO.setEvaluatedConclusion(securityEvaluation.getEvaluatedConclusion());

        List<TMaterialLinked> materialLinked = materialLinkedService.list(new LambdaQueryWrapper<TMaterialLinked>()
                .eq(TMaterialLinked::getLinkedId, securityEvaluation.getId())
                .eq(TMaterialLinked::getLinkedType, IecicLinkedTypeEnum.CIR.getType()));
        if (CollectionUtils.isEmpty(materialLinked)) {
            return Result.OK(ingredientEvaluateDTO);
        }

        List<MaterialDTO> materialDTOS = materialLinked.stream().map(tMaterialLinked -> {
            MaterialDTO materialDTO = new MaterialDTO();
            TProductMaterial productMaterial = productMaterialService.getById(tMaterialLinked.getMaterialId());
            if (ObjectUtil.isEmpty(productMaterial)) {
                return materialDTO;
            }
            BeanUtils.copyProperties(productMaterial, materialDTO);
            return materialDTO;
        }).collect(Collectors.toList());

        ingredientEvaluateDTO.setMaterialList(materialDTOS);
        return Result.OK(ingredientEvaluateDTO);
    }

    /**
     * 成分风险物质危害列表
     *
     * @param productId
     * @return
     */
    public Result<List<IngredientRiskDTO>> queryIngredientRiskList(Long productId) {
        List<TFormula> formulas = formulaService.list(new LambdaQueryWrapper<TFormula>()
                .eq(TFormula::getProductId, productId));
        if (CollectionUtils.isEmpty(formulas)) {
            log.error("产品配方信息不存在，productId:{}", productId);
            return Result.OK(Lists.newArrayList());
        }
        formulas = formulas.stream()
                .sorted(new Comparator<TFormula>() {
                    @Override
                    public int compare(TFormula o1, TFormula o2) {
                        if (StringUtils.isEmpty(o1.getMaterialContent()) || StringUtils.isEmpty(o2.getMaterialContent())) {
                            return 1;
                        }
                        return new BigDecimal(o2.getMaterialContent()).compareTo(new BigDecimal(o1.getMaterialContent()));
                    }
                })
                .collect(Collectors.toList());
        List<IngredientRiskDTO> ingredientRiskDTOS = formulas.stream().map(m -> {
            IngredientRiskDTO ingredientRiskDTO = new IngredientRiskDTO();
            ingredientRiskDTO.setId(m.getId());
            ingredientRiskDTO.setCName(m.getCnName());
            ingredientRiskDTO.setProductId(m.getProductId());
            ingredientRiskDTO.setParentId(m.getParentId());
            List<TFormulaRisk> formulaRisks = formulaRiskService.list(new LambdaQueryWrapper<TFormulaRisk>()
                    .eq(TFormulaRisk::getFormulaId, m.getId()));
            if (CollectionUtils.isEmpty(formulaRisks)) {
                return ingredientRiskDTO;
            }
            List<RiskMatterDTO> riskMatterDTOS = formulaRisks.stream().map(item -> {
                RiskMatterDTO riskMatterDTO = new RiskMatterDTO();
                riskMatterDTO.setRiskId(item.getId());
                riskMatterDTO.setRiskName(item.getRiskName());
                riskMatterDTO.setRemark(item.getRemark());
                if (StringUtils.isNotEmpty(item.getDetailInfo())) {
                    riskMatterDTO.setDetailInfo(JSON.parseObject(item.getDetailInfo(), new TypeReference<List<String>>() {
                    }));
                }

                //查询风险物质关联附录
                List<TMaterialLinked> materialLinked = materialLinkedService.list(new LambdaQueryWrapper<TMaterialLinked>()
                        .eq(TMaterialLinked::getLinkedId, item.getId())
                        .eq(TMaterialLinked::getLinkedType, IecicLinkedTypeEnum.RISK.getType()));
                if (CollectionUtils.isEmpty(materialLinked)) {
                    return riskMatterDTO;
                }

                List<MaterialDTO> materialDTOS = materialLinked.stream().map(tMaterialLinked -> {
                    TProductMaterial productMaterial = productMaterialService.getById(tMaterialLinked.getMaterialId());
                    MaterialDTO materialDTO = new MaterialDTO();
                    BeanUtils.copyProperties(productMaterial, materialDTO);
                    return materialDTO;
                }).collect(Collectors.toList());
                riskMatterDTO.setMaterialDTOS(materialDTOS);
                return riskMatterDTO;
            }).collect(Collectors.toList());
            ingredientRiskDTO.setRiskMatterDTOS(riskMatterDTOS);
            return ingredientRiskDTO;
        }).collect(Collectors.toList());
        return Result.OK(ingredientRiskDTOS);
    }

    /**
     * 更新成分信息
     *
     * @param vo
     * @return
     */
    @Transactional
    @DS("cosmetic-datasource")
    public Result<?> updateIngredientByPrimary(IngredientUpdateVO vo) {
        TSecurityEvaluation securityEvaluation = securityEvaluationService.getById(vo.getId());
        Optional.ofNullable(securityEvaluation).orElseThrow(() -> new JeecgBootException("成分不存在"));
        securityEvaluation.setTechnicalSpecification(vo.getTechnicalDesc());
        securityEvaluation.setAuthorityConclusion(vo.getAuthorityConclusion());
        securityEvaluation.setEvaluatedConclusion(vo.getEvaluatedConclusion());
        boolean flag = securityEvaluationService.updateById(securityEvaluation);

        materialLinkedService.remove(new LambdaQueryWrapper<TMaterialLinked>()
                .eq(TMaterialLinked::getLinkedId, securityEvaluation.getId())
                .eq(TMaterialLinked::getLinkedType, IecicLinkedTypeEnum.CIR.getType()));
        if (!CollectionUtils.isEmpty(vo.getMaterialIds())) {
            //插入成分文献关联信息
            vo.getMaterialIds().forEach(f -> {
                TMaterialLinked materialLinked = new TMaterialLinked();
                materialLinked.setMaterialId(f);
                materialLinked.setLinkedId(securityEvaluation.getId());
                materialLinked.setLinkedType(IecicLinkedTypeEnum.CIR.getType());
                materialLinkedService.save(materialLinked);
            });
        }
        return flag ? Result.OK() : Result.error("修改成分信息失败");
    }

    /**
     * 查询风险物质详情
     *
     * @param id
     * @return
     */
    public Result<IngredientRiskDTO> queryIngredientRiskDetail(Long id) {
        TFormula formula = formulaService.getById(id);
        Optional.ofNullable(formula).orElseThrow(() -> new JeecgBootException("配方成分不存在"));
        IngredientRiskDTO ingredientRiskDTO = new IngredientRiskDTO();
        ingredientRiskDTO.setId(formula.getId());
        ingredientRiskDTO.setCName(formula.getCnName());
        ingredientRiskDTO.setProductId(formula.getProductId());
        List<TFormulaRisk> formulaRisks = formulaRiskService.list(new LambdaQueryWrapper<TFormulaRisk>()
                .eq(TFormulaRisk::getFormulaId, formula.getId()));
        if (CollectionUtils.isEmpty(formulaRisks)) {
            throw new JeecgBootException("未关联风险物质，无法查看");
        }
        List<RiskMatterDTO> riskMatterDTOS = formulaRisks.stream().map(item -> {
            RiskMatterDTO riskMatterDTO = new RiskMatterDTO();
            riskMatterDTO.setRiskId(item.getId());
            riskMatterDTO.setRiskName(item.getRiskName());
            riskMatterDTO.setRemark(item.getRemark());
            if (StringUtils.isNotEmpty(item.getDetailInfo())) {
                riskMatterDTO.setDetailInfo(JSON.parseObject(item.getDetailInfo(), new TypeReference<List<String>>() {
                }));
            }
            //查询风险物质关联附录
            List<TMaterialLinked> materialLinked = materialLinkedService.list(new LambdaQueryWrapper<TMaterialLinked>()
                    .eq(TMaterialLinked::getLinkedId, item.getId())
                    .eq(TMaterialLinked::getLinkedType, IecicLinkedTypeEnum.RISK.getType()));
            if (CollectionUtils.isEmpty(materialLinked)) {
                return riskMatterDTO;
            }
            List<MaterialDTO> materialDTOS = materialLinked.stream().map(materialId -> {
                TProductMaterial productMaterial = productMaterialService.getById(materialId.getMaterialId());
                MaterialDTO materialDTO = new MaterialDTO();
                BeanUtils.copyProperties(productMaterial, materialDTO);
                return materialDTO;
            }).collect(Collectors.toList());
            riskMatterDTO.setMaterialDTOS(materialDTOS);
            return riskMatterDTO;
        }).collect(Collectors.toList());
        ingredientRiskDTO.setRiskMatterDTOS(riskMatterDTOS);
        return Result.OK(ingredientRiskDTO);
    }

    /**
     * 修改风险物质备注
     *
     * @param vo
     * @return
     */
    @Transactional
    @DS("cosmetic-datasource")
    public Result<?> updateFormulaRiskByPrimary(List<FormulaRiskUpdateVO> vo) {
        if (CollectionUtils.isEmpty(vo)) {
            return Result.error("参数为空，修改失败");
        }
        vo.forEach(f -> {
            TFormulaRisk formulaRisk = formulaRiskService.getById(f.getRiskId());
            if (ObjectUtil.isEmpty(formulaRisk)) {
                return;
            }
            formulaRisk.setRemark(f.getRemark());
            if (!CollectionUtils.isEmpty(f.getDetailJson())) {
                formulaRisk.setDetailInfo(JSON.toJSONString(f.getDetailJson()));
            }
            //更新风险物质信息
            formulaRiskService.updateById(formulaRisk);
            //删除关联信息
            materialLinkedService.remove(new LambdaQueryWrapper<TMaterialLinked>()
                    .eq(TMaterialLinked::getLinkedId, f.getRiskId())
                    .eq(TMaterialLinked::getLinkedType, IecicLinkedTypeEnum.RISK.getType()));
            if (CollectionUtils.isEmpty(f.getMaterialIds())) {
                return;
            }
            //重新插入关系数据
            f.getMaterialIds().forEach(id -> {
                TMaterialLinked materialLinked = new TMaterialLinked();
                materialLinked.setMaterialId(id);
                materialLinked.setLinkedId(f.getRiskId());
                materialLinked.setLinkedType(IecicLinkedTypeEnum.RISK.getType());
                materialLinkedService.save(materialLinked);
            });

        });

        return Result.OK();
    }

}
